import java.util.concurrent.*;

/**
 * Created by Kate on 11.12.2014.
 */
public class VariableCapacityConnectionPool implements ConnectionPool {
    private int init;
    private int max;
    private long keepAliveTime;
    private final TimeUnit unit;
    private final ConnectionSource src;

    private final BlockingQueue<Object> dynamicConnections;
    private final ScheduledExecutorService executorService;
    private final FixedCapacityConnectionPool fixedCapacityConnectionPool;

    public VariableCapacityConnectionPool(int init, int max, long keepAliveTime, TimeUnit unit, ConnectionSource src) {

        dynamicConnections = new ArrayBlockingQueue<Object>(max - init, true);
        executorService = Executors.newScheduledThreadPool(1);

        fixedCapacityConnectionPool = new FixedCapacityConnectionPool(init, src);

        this.init = init;
        this.max = max;
        this.keepAliveTime = keepAliveTime;
        this.unit = unit;
        this.src = src;
    }

    private Object NonBlockingOpenDynamicConnection(ConnectionSource src, long keepAliveTime, TimeUnit unit) {
        final Object connection = src.open();

        dynamicConnections.add(connection);

        Runnable toRemoveTask = new Runnable() {
            @Override
            public void run() {
                synchronized (dynamicConnections) {
                    if (dynamicConnections.size() > max - init) {
                        dynamicConnections.remove(connection);
                    }
                }
            }
        };

        executorService.schedule(toRemoveTask, keepAliveTime, unit);

        return connection;
    }

    private Object BlockingOpenDynamicConnection(ConnectionSource src, long keepAliveTime, TimeUnit unit) throws InterruptedException {
        final Object connection = src.open();

        dynamicConnections.put(connection);

        Runnable toRemoveTask = new Runnable() {
            @Override
            public void run() {
                synchronized (dynamicConnections) {
                    if (dynamicConnections.size() > max - init) {
                        dynamicConnections.remove(connection);
                    }
                }
            }
        };

        executorService.schedule(toRemoveTask, keepAliveTime, unit);

        return connection;
    }

    @Override
    public Object get() throws InterruptedException {
        Object connection = fixedCapacityConnectionPool.tryGet();
        if (connection != null) {
            return connection;
        }
        return BlockingOpenDynamicConnection(src, keepAliveTime, unit);
    }

    @Override
    public Object tryGet() {
        Object connection = fixedCapacityConnectionPool.tryGet();
        if (connection != null) {
            return connection;
        }

        if (dynamicConnections.remainingCapacity() == 0) {
            return null;
        }

        return NonBlockingOpenDynamicConnection(src, keepAliveTime, unit);
    }

    @Override
    public Object tryGet(long time, TimeUnit unit) throws InterruptedException {
        return null;
    }

    @Override
    public void release(Object object) {

    }
}
